home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-01-07 | 54.0 KB | 1,689 lines |
- /*
- * machTrap.s --
- *
- * Traps for sun4.
- *
- * Copyright 1989 Regents of the University of California
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- */
-
- .seg "data"
- .asciz "$Header: /cdrom/src/kernel/Cvsroot/kernel/mach/sun4.md/machTrap.s,v 9.15 93/01/06 20:09:19 mgbaker Exp $ SPRITE (Berkeley)"
- .align 8
- .seg "text"
-
- #include "user/proc.h"
- #include "machConst.h"
- #include "machAsmDefs.h"
-
- .align 8
- .seg "text"
-
- /*
- * ----------------------------------------------------------------------
- *
- * MachTrap --
- *
- * All traps except window overflow and window underflow go through
- * this trap handler. This handler is used to save the appropriate
- * state, set up the kernel stack, and then jump to the correct
- * handler depending on the type of trap. The handler assumes that
- * we have saved the trap %psr into %CUR_PSR_REG before we get here (as
- * an instruction in the vector table that made us branch here).
- *
- * Window overflow and underflow jump directly from the vector table
- * to their handlers, since in the most common cases they do not need
- * to save state and they should be as fast as possible.
- *
- * The scheme of things:
- *
- * 1) Check to see if we're in an invalid window. If so, deal first with
- * window overflow.
- * 2) Now that it's safe to overwrite our out registers, update the stack
- * pointer. If coming from user mode, this means pulling the kernel
- * stack pointer out of the state structure and adding the appropriate
- * amount. Otherwise, it means just means adding the appropriate amount to
- * our %fp.
- * 3) Save the rest of the trap state (globals) to the stack. Note that
- * although locals and ins contain trap state (ins are our caller's outs
- * which we shouldn't mess up, and the psr and other state registers are
- * in our locals) we need not save them explicitly, since they will be
- * saved as a part of the normal window overflow and underflow. There
- * are exceptions to this, such as context switching or debugger traps,
- * where we must explicitly save the window to the stack, but the
- * exceptions must take care of this for themselves.
- * 4) Re-enable traps and disable interrupts. Traps must be disabled
- * so that if we get another window overflow or underflow,
- * we'll be able to deal with it.
- * 5) Figure out what handler to call and call it.
- *
- * The handler must call our return-from-trap post-amble, rather than
- * return here.
- *
- * If a window underflow or overflow trap discovers that it must do
- * something tricky, such as call Vm_PageIn, that requires turning
- * on traps and interrupts, then it will call MachTrap to save state
- * for it. This is why there are entries in MachTrap for window
- * overflow and underflow. These are the entries to take care of the
- * "slow trap" overflows and underflows.
- *
- * Results:
- * None.
- *
- * Side effects:
- * We make space on our kernel stack to save this trap window.
- * If it is a user process entering the kernel, then we make its trapRegs
- * field point to this save-window area on the kernel stack.
- *
- * ----------------------------------------------------------------------
- */
- .global _MachTrap
- _MachTrap:
- /*
- * Save the state registers. This is safe, since we're saving them
- * to local registers and we can do this even if we've entered
- * into an invalid window.
- * In the vector table that jumps here, we have already saved
- * the %psr into %CUR_PSR_REG. The trap instruction itself saved
- * the trap pc and next pc into local registers %CUR_PC_REG and
- * %NEXT_PC_REG. This means we must save only the %tbr and the %y
- * registers.
- */
- mov %tbr, %CUR_TBR_REG
- mov %y, %CUR_Y_REG
- /*
- * Are we in an invalid window?
- */
- MACH_INVALID_WINDOW_TEST()
- be WindowOkay
- nop
- /*
- * Deal with window overflow - put return addr in SAFE_TEMP since
- * the overflow handler will look for the return address there..
- * It is okay to do this, even if we got here after due to a slow
- * overflow trap due to special action needed, because if we did that,
- * then we've already taken care of the overflow problem and so we
- * won't get it here and so we won't be overwriting the return address
- * in SAFE_TEMP.
- */
- set MachWindowOverflow, %VOL_TEMP1
- jmpl %VOL_TEMP1, %SAFE_TEMP
- nop
- WindowOkay:
- /*
- * Now that we know our out registers are safe to use, since we're
- * in a valid window, update our stack pointer.
- * If coming from user mode, I need to get kernel sp from
- * state structure. If we came from kernel
- * mode, just subtract a stack frame from the current frame pointer and
- * continue. To see if we came from user mode, we look at the
- * previous state bit (PS) in the processor state register.
- * I set up the stack pointer in the delay slot of the branch if I came
- * from kernel mode, so it's as fast as possible. I annul the
- * instruction if it turns out to be a user stack.
- * We must give the stack a full state frame so that C routines
- * we call will have space to store their arguments. (System calls,
- * for example!)
- *
- * NOTE: The amount we bump up the stack by here must
- * agree with the debugger stack test in the window underflow routine,
- * so that we don't trash our stack when returning from the
- * debugger!!!!!
- */
- andcc %CUR_PSR_REG, MACH_PS_BIT, %g0 /* previous state? */
- bne,a DoneWithUserStuff /* was kernel mode */
- add %fp, -MACH_SAVED_STATE_FRAME, %sp /* set kernel sp */
- MACH_GET_CUR_STATE_PTR(%VOL_TEMP2, %VOL_TEMP1) /* into %VOL_TEMP2 */
- add %VOL_TEMP2, MACH_KSP_OFFSET, %VOL_TEMP1 /* &(machPtr->ksp) */
- ld [%VOL_TEMP1], %sp /* machPtr->ksp */
- set (MACH_KERN_STACK_SIZE - MACH_SAVED_STATE_FRAME), %VOL_TEMP1
- add %sp, %VOL_TEMP1, %sp
- /*
- * Since we came from user mode, set the trapRegs field of the
- * current state structure to the value of our new kernel sp,
- * since the trap regs are saved on top of the stack.
- */
- add %VOL_TEMP2, MACH_TRAP_REGS_OFFSET, %VOL_TEMP2
- st %sp, [%VOL_TEMP2]
-
- DoneWithUserStuff:
- /* Test stack alignment here?? */
-
- /*
- * This only saves the globals to the stack. The locals
- * and ins make it there through normal overflow and underflow.
- *
- * NOTE that we cannot trash %g1 even after saving the global
- * registers, since that is the register that contains the system
- * call number for system call traps!
- */
- MACH_SAVE_GLOBAL_STATE()
-
- /* traps on, maskable interrupts off */
- MACH_SR_HIGHPRIO()
-
- /*
- * It is tedious to do all these serial comparisons against the
- * trap type, so this should be changed to a jump table. It's this
- * way right now because I'm working on other things and this is
- * easy for debugging.
- */
- and %CUR_TBR_REG, MACH_TRAP_TYPE_MASK, %VOL_TEMP1 /* get trap */
-
- cmp %VOL_TEMP1, MACH_LEVEL0_INT
- bl NotAnInterrupt
- nop
- cmp %VOL_TEMP1, MACH_LEVEL15_INT
- bgu NotAnInterrupt
- nop
- /*
- * It's an interrupt.
- */
- b MachHandleInterrupt
- nop
-
- NotAnInterrupt:
-
- cmp %VOL_TEMP1, MACH_TRAP_SYSCALL /* system call */
- be MachSyscallTrap
- nop
-
- cmp %VOL_TEMP1, MACH_INSTR_ACCESS /* instruction fault */
- be MachHandlePageFault
- nop
-
- cmp %VOL_TEMP1, MACH_DATA_ACCESS /* data fault */
- be MachHandlePageFault
- nop
-
- cmp %VOL_TEMP1, MACH_TRAP_SIG_RETURN /* ret from handler */
- be _MachReturnFromSignal
- nop
-
- cmp %VOL_TEMP1, MACH_TRAP_FLUSH_WINDOWS /* flush window trap */
- be MachFlushWindowsToStackTrap
- nop
-
- cmp %VOL_TEMP1, MACH_TRAP_UNIX_SYSCALL /* unix syscall */
- be MachUnixSyscallTrap
- nop
-
- cmp %VOL_TEMP1, MACH_TRAP_INSTR_2 /* Dynamic linking */
- be MachLinkTrap
- nop
-
- /*
- * These next few are handled by C routines, and we want them to
- * return to MachReturnFromTrap, so set that address as the return pc.
- */
- cmp %VOL_TEMP1, MACH_ILLEGAL_INSTR /* illegal instr */
- set _MachReturnFromTrap, %RETURN_ADDR_REG /* set return pc */
- mov %VOL_TEMP1, %o0
- mov %CUR_PC_REG, %o1
- mov %CUR_PSR_REG, %o2
- be _MachHandleTrap /* C routine */
- nop
-
- cmp %VOL_TEMP1, MACH_PRIV_INSTR /* privileged instr */
- set _MachReturnFromTrap, %RETURN_ADDR_REG /* set return pc */
- mov %VOL_TEMP1, %o0
- mov %CUR_PC_REG, %o1
- mov %CUR_PSR_REG, %o2
- be _MachHandleTrap /* C routine */
- nop
-
- cmp %VOL_TEMP1, MACH_MEM_ADDR_ALIGN /* addr not aligned */
- set _MachReturnFromTrap, %RETURN_ADDR_REG /* set return pc */
- mov %VOL_TEMP1, %o0
- mov %CUR_PC_REG, %o1
- mov %CUR_PSR_REG, %o2
- be _MachHandleTrap /* C routine */
- nop
-
- cmp %VOL_TEMP1, MACH_TAG_OVERFLOW /* tagged instr ovfl */
- set _MachReturnFromTrap, %RETURN_ADDR_REG /* set return pc */
- mov %VOL_TEMP1, %o0
- mov %CUR_PC_REG, %o1
- mov %CUR_PSR_REG, %o2
- be _MachHandleTrap /* C routine */
- nop
-
- cmp %VOL_TEMP1, MACH_FP_EXCEP /* fp unit badness */
- set _MachReturnFromTrap, %RETURN_ADDR_REG /* set return pc */
- mov %VOL_TEMP1, %o0
- mov %CUR_PC_REG, %o1
- mov %CUR_PSR_REG, %o2
- be _MachHandleTrap /* C routine */
- nop
-
- cmp %VOL_TEMP1, MACH_FP_DISABLED /* fp unit disabled */
- set _MachReturnFromTrap, %RETURN_ADDR_REG /* set return pc */
- mov %VOL_TEMP1, %o0
- mov %CUR_PC_REG, %o1
- mov %CUR_PSR_REG, %o2
- be _MachHandleTrap /* C routine */
- nop
-
- /*
- * We never get here directly from the window overflow trap.
- * Instead, what this means is that after handling a window
- * overflow trap, on the way out we had to deal with a special
- * user action. Because we don't save state, etc, on a regular
- * window overflow, we've executed the above code to save the
- * state for us. Now we just want to go back and deal with the
- * special overflow.
- */
- cmp %VOL_TEMP1, MACH_WINDOW_OVERFLOW /* weird overflow */
- be MachReturnToOverflowWithSavedState
- nop
-
- cmp %VOL_TEMP1, MACH_WINDOW_UNDERFLOW /* weird underflow */
- be MachReturnToUnderflowWithSavedState
- nop
-
- cmp %VOL_TEMP1, MACH_TRAP_DEBUGGER /* enter debugger */
- be _MachHandleDebugTrap
- nop
-
- b _MachHandleDebugTrap /* all others to debugger */
- nop
-
-
- /*
- * ----------------------------------------------------------------------
- *
- * MachReturnFromTrap --
- *
- * Go through the inverse of MachTrap. The trap handlers that MachTrap
- * called return to here rather than MachTrap.
- *
- * The scheme of things:
- *
- * 1) Determine if we are returning to user mode. If so, then we must
- * check the specialHandling flag. If it is set, then we must call
- * MachUserAction.
- * 2) If we called MachUserAction, then we must check its return value
- * to see if we need to deal with any signals. If we do, then
- * we call MachHandleSignal(). It returns to user mode itself via
- * a rett instruction, so we don't come back here until the
- * return-from-signal trap that the user ends up executing to return to
- * the kernel from a signal.
- * 3) For both returns to user mode and returns to kernel mode, we
- * must next check if we would return to an invalid window. If so,
- * we must make it valid or we will get a watchdog reset. We may
- * call the window underflow routine to do this. But, if we are
- * returning to user mode, we must check to make sure the user stack
- * is resident, since the underflow routine can't get any page faults.
- * If the user stack isn't resident, we page it in.
- * 4) Finally, we disable traps again (or the rett instruction will
- * give us a watchdog reset), restore the global registers, restore
- * the %tbr, %y registers, restore the %psr to the trap psr, and rett
- * (return from trap) to the saved trap pc and next pc.
- *
- * Results:
- * None.
- *
- * Side effects:
- * We jump back to where we came from. If we came from a system call
- * or certain other traps, we'll actually return to where we came from
- * plus 8, or else we would re-execute the system call instruction.
- * The addition of 8 was done by the individual handlers that know
- * whether or not they would need to do this.
- *
- * If a user process has a bad stack pointer, we will kill it here and
- * print out a message.
- *
- * ----------------------------------------------------------------------
- */
- .global _MachReturnFromTrap
- _MachReturnFromTrap:
- /* Are we a user or kernel process? */
- andcc %CUR_PSR_REG, MACH_PS_BIT, %g0
- bne NormalReturn
- nop
- /* Do we need to take a special action? Check special handling flag. */
- MACH_GET_CUR_PROC_PTR(%VOL_TEMP1)
- sethi %hi(_machSpecialHandlingOffset), %VOL_TEMP2
- ld [%VOL_TEMP2 + %lo(_machSpecialHandlingOffset)], %VOL_TEMP2
- add %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP1
- ld [%VOL_TEMP1], %VOL_TEMP1
- tst %VOL_TEMP1
- be NormalReturn
- nop
- call _MachUserAction
- nop
- /* Check if we must handle a signal */
- tst %RETURN_VAL_REG
- be NormalReturn
- nop
- cmp %RETURN_VAL_REG, 2
- be DoUnixSignal
- nop
- /*
- * We must handle a signal. Call the leaf routine MachSetupSignal.
- * It does its own return from trap, so we don't come back here when
- * it's done!
- */
- call _MachHandleSignal
- nop
- DoUnixSignal:
- MACH_RESTORE_WINDOW_FROM_STACK()
- nop
- sub %fp, 0x8f0, %fp
- nop
- NormalReturn:
- MACH_UNDERFLOW_TEST()
- be UnderflowOkay
- nop
- /*
- * Make sure stack is resident. We don't want to get a page
- * fault in the underflow routine, because it moves into the window
- * to restore and so its calls to Vm code would move into this
- * window and overwrite it! First check if it's a user process, since
- * that should be the only case where the stack isn't resident.
- */
- andcc %CUR_PSR_REG, MACH_PS_BIT, %g0
- bne CallUnderflow
- nop
- /*
- * It's a user process, so check residence and protection fields of pte.
- * Before anything we check stack alignment.
- */
- andcc %fp, 0x7, %g0
- bne KillUserProc
- nop
- MACH_CHECK_FOR_FAULT(%fp, %VOL_TEMP1)
- be CheckNextFault
- nop
- /*
- * Call VM Stuff with the %fp which will be stack pointer in
- * the window we restore.
- */
- QUICK_ENABLE_INTR(%VOL_TEMP1)
- mov %fp, %o0
- clr %o1 /* also check for protection????? */
- call _Vm_PageIn, 2
- nop
- QUICK_DISABLE_INTR(%VOL_TEMP1)
- tst %RETURN_VAL_REG
- bne KillUserProc
- nop
- CheckNextFault:
- /* Check other extreme of area we'd touch */
- add %fp, (MACH_SAVED_WINDOW_SIZE - 4), %o0
- MACH_CHECK_FOR_FAULT(%o0, %VOL_TEMP1)
- be CallUnderflow
- nop
- QUICK_ENABLE_INTR(%VOL_TEMP1)
- clr %o1
- call _Vm_PageIn, 2
- nop
- QUICK_DISABLE_INTR(%VOL_TEMP1)
- tst %RETURN_VAL_REG
- be CallUnderflow
- nop
- KillUserProc:
- /*
- * Kill user process! Its stack is bad.
- */
- MACH_SR_HIGHPRIO() /* traps back on for overflow from printf */
- set _MachReturnFromTrapDeathString, %o0
- call _printf, 1
- nop
- MACH_GET_CUR_PROC_PTR(%o0) /* procPtr in %o0 */
- sethi %hi(_machGenFlagsOffset), %o1
- ld [%o1 + %lo(_machGenFlagsOffset)], %o1
- add %o0, %o1, %o1
- ld [%o1], %o1
- sethi %hi(_machForeignFlag), %o2
- ld [%o2 + %lo(_machForeignFlag)], %o2
- andcc %o1, %o2, %o1 /* Is this a migrated proc? */
- be DebugIt
- nop
- set PROC_TERM_DESTROYED, %o0 /* If so, kill it. */
- set PROC_BAD_STACK, %o1
- clr %o2
- call _Proc_ExitInt, 3
- nop
- DebugIt: /* Else, make it debuggable. */
- MACH_GET_CUR_PROC_PTR(%o0) /* procPtr in %o0 */
- call _Sig_CheckForKill, 1 /* kill proc if KILL signal */
- nop
- MACH_GET_CUR_PROC_PTR(%o0) /* procPtr in %o0 */
- set TRUE, %o1 /* debug TRUE */
- set PROC_TERM_DESTROYED, %o2
- set PROC_BAD_STACK, %o3
- clr %o4
- call _Proc_SuspendProcess, 5
- nop
- ba DebugIt /* proc should loop if continued */
- nop
-
- CallUnderflow:
- set MachWindowUnderflow, %VOL_TEMP1
- jmpl %VOL_TEMP1, %RETURN_ADDR_REG
- nop
- UnderflowOkay:
- MACH_DISABLE_TRAPS(%VOL_TEMP1, %VOL_TEMP2)
- MACH_RESTORE_GLOBAL_STATE()
- /* restore y reg */
- mov %CUR_Y_REG, %y
-
- /* restore tbr reg */
- mov %CUR_TBR_REG, %tbr
- /* restore psr */
- MACH_RESTORE_PSR()
- jmp %CUR_PC_REG
- rett %NEXT_PC_REG
- nop
-
- /*
- * ----------------------------------------------------------------------
- *
- * MachHandleWindowOverflowTrap --
- *
- * Trap entrance to the window overflow handler. We try to get in and
- * out of here as quickly as possible in the normal case. Unlike
- * most traps, we jump here directly from the trap table, and do not
- * go through the usual MachTrap preamble. This means no
- * state has been saved and we have no stack pointer. This in turn means
- * that we cannot turn traps on, since we have no saved state and no place
- * to save the trap registers. This routine sets up a return
- * address, calls the overflow handler, restores the psr, and
- * returns from the trap. It assumes that the trap psr was stored in
- * %CUR_PSR_REG before jumping here (in the trap vector table).
- *
- * When we return to this routine from the actual overflow handling
- * routine, we check to see if we're returning to user mode. If we aren't
- * we can just leave this routine normally. If we're returning to user
- * mode, however, we must check for some special cases. It may be that
- * the user stack wasn't resident and that we had to save the overflow
- * window to a special internal buffer rather than the user stack. If this
- * is so, we require extra processing. So we call MachTrap to save state
- * for us and then call MachReturnFromTrap, which will handle the fact
- * that the window was saved to an internal buffer. The effect of all of
- * this is to turn the overflow trap into a "slow overflow trap" that goes
- * through the usual trap preamble and postamble.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The mach state structure may be modified if this is a user window
- * and its stack isn't resident, causing us to save the window to
- * the buffers in the mach state structure.
- *
- * ----------------------------------------------------------------------
- */
- .global MachHandleWindowOverflowTrap
- MachHandleWindowOverflowTrap:
- /*
- * Call actual overflow handler.
- */
- set MachWindowOverflow, %VOL_TEMP1
- jmpl %VOL_TEMP1, %SAFE_TEMP
- nop
- /*
- * If returning to user mode, check special handling flags here to
- * see if we need to do any fancy processing (due to the user's
- * stack not being resident so we had to save the window to an internal
- * buffer instead).
- */
- andcc %CUR_PSR_REG, MACH_PS_BIT, %g0 /* user or kernel? */
- bne NormalOverflowReturn
- nop
- /* Do we need to take a special action? Check special handling flag. */
- MACH_GET_CUR_PROC_PTR(%VOL_TEMP1)
- sethi %hi(_machSpecialHandlingOffset), %VOL_TEMP2
- ld [%VOL_TEMP2 + %lo(_machSpecialHandlingOffset)], %VOL_TEMP2
- add %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP1
- ld [%VOL_TEMP1], %VOL_TEMP1
- tst %VOL_TEMP1
- be NormalOverflowReturn
- nop
- /*
- * We need to save state and allocate space on the stack, etc.
- * Run through regular trap preamble to do this. The trap preamble
- * will then return us to here. This is all in preparation for
- * calling MachReturnFromTrap, since that will call MachUserAction
- * to deal with the window saved to the internal buffer.
- */
- call _MachTrap
- nop
- MachReturnToOverflowWithSavedState:
- /*
- * Now call trap postamble to restore state and push saved window to
- * the user stack. MachReturnFromTrap will return to user mode, so
- * we will not come back here after this call!
- */
- call _MachReturnFromTrap
- nop
-
- /*
- * This was a normal fast window overflow trap, so just return.
- */
- NormalOverflowReturn:
- MACH_RESTORE_PSR()
- jmp %CUR_PC_REG
- rett %NEXT_PC_REG
- nop
-
- /*
- * ----------------------------------------------------------------------
- *
- * MachWindowOverflow --
- *
- * Window overflow handler. It's set up so that it can be called from the
- * fast window overflow trap handler, or it can be called directly from
- * MachTrap for any trap that causes us to land inside an invalid window.
- *
- * The window we've trapped into is currently invalid. We want to
- * make it valid. We do this by moving one window further, saving that
- * window to the stack, marking it as the new invalid window, and then
- * moving back to the window that we trapped into. It is then valid
- * and usable. Note that we move first to the window to save and then
- * mark it invalid. In the other order we would get another overflow
- * trap, but with traps turned off, which causes a watchdog reset...
- * Note that %sp should point to the lowest address usable
- * word in the current stack frame. %fp is the %sp of the
- * caller's stack frame, so the first (highest in memory) usable word
- * of a current stack frame is (%fp - 4).
- *
- * This code will be called with traps DISABLED, so nothing in this
- * code is allowed to cause a trap. This means no procedure calls are
- * allowed.
- *
- * Results:
- * Returns to the address %SAFE_TEMP + 8.
- *
- * Side effects:
- * The window invalid mask changes and a register window is saved.
- * The mach state structure may change if we need to save this window
- * into its internal buffers (if it's a user window and the stack isn't
- * resident).
- *
- * ----------------------------------------------------------------------
- */
- .global MachWindowOverflow
- MachWindowOverflow:
- /*
- * We enter inside of an invalid window, so we can't use in registers,
- * out registers or global registers to begin with.
- * We temporarily clear out some globals since we won't be able to
- * use locals in window we move to before saving it. Using them would
- * mess them up for window's owner.
- */
- mov %g3, %VOL_TEMP1
- mov %g4, %VOL_TEMP2
- save /* move to the window to save */
- MACH_ADVANCE_WIM(%g3, %g4) /* reset %wim to current window */
- /*
- * If this is a user window, then see if stack space is resident.
- * If it is, go ahead, but if not, then set special handling and
- * save to buffers. It's fairly dreadful that we must do all this
- * checking here, since this will slow down all the overflow traps.
- */
- set MACH_MAX_USER_STACK_ADDR, %g3 /* %sp in user space? */
- subcc %g3, %sp, %g0 /* need sp < highest addr */
- bleu NotUserStack
- nop
- set MACH_FIRST_USER_ADDR, %g3 /* need sp >= lowest addr */
- subcc %sp, %g3, %g0
- bgeu UserStack
- nop
- NotUserStack:
- set MACH_STACK_BOTTOM, %g3
- subcc %sp, %g3, %g0 /* need sp >= lowest addr */
- blu BadStack
- nop
- set VMMACH_DEV_START_ADDR, %g3 /* need sp < highest addr */
- subcc %g3, %sp, %g0
- bgu NormalOverflow
- nop
- BadStack:
- /*
- * Assume it was a user process's bad stack pointer. We can't kill
- * the process here, so just take over the window and the user process
- * will die a terrible death later. To take over the window, we just
- * return, since we've already advanced the %wim.
- */
- ba ReturnFromOverflow
- nop
- UserStack:
- /*
- * If the stack alignment is bad, we just take over the window and
- * assume the user process will die a horrible death later on.
- */
- andcc %sp, 0x7, %g0
- bne ReturnFromOverflow
- nop
-
- /* Would saving window cause a page fault? */
- MACH_CHECK_FOR_FAULT(%sp, %g3)
- bne SaveToInternalBuffer
- nop
-
- /* check other address extreme */
- add %sp, (MACH_SAVED_WINDOW_SIZE - 4), %g4
- MACH_CHECK_FOR_FAULT(%g4, %g3)
- be NormalOverflow
- nop
- SaveToInternalBuffer:
- /*
- * The stack wasn't resident, so we must save to an internal buffer
- * and set the special handling flag.
- * We update the saved mask to show that this window had to be saved
- * to the internal buffers. We do this by or'ing in the value of
- * the current window invalid mask, since it's been set to point to
- * this window we must save.
- */
- MACH_GET_CUR_STATE_PTR(%g3, %g4) /* puts machStatePtr in %g3 */
- sethi %hi(_machCurStatePtr), %g4
- /* update it */
- st %g3, [%g4 + %lo(_machCurStatePtr)]
- add %g3, MACH_SAVED_MASK_OFFSET, %g3
- ld [%g3], %g3
- mov %wim, %g4
- or %g3, %g4, %g4
- sethi %hi(_machCurStatePtr), %g3
- ld [%g3 + %lo(_machCurStatePtr)], %g3
- add %g3, MACH_SAVED_MASK_OFFSET, %g3
- st %g4, [%g3]
-
- /*
- * Get and set the special handling flag in the current process state.
- */
- MACH_GET_CUR_PROC_PTR(%g3)
- sethi %hi(_machSpecialHandlingOffset), %g4
- ld [%g4 + %lo(_machSpecialHandlingOffset)], %g4
- add %g3, %g4, %g3
- mov 0x1, %g4
- st %g4, [%g3]
-
- /*
- * Save the current user stack pointer for this window.
- */
- sethi %hi(_machCurStatePtr), %g3
- ld [%g3 + %lo(_machCurStatePtr)], %g3
- add %g3, MACH_SAVED_SPS_OFFSET, %g3
- mov %psr, %g4
- and %g4, MACH_CWP_BITS, %g4
- /* Multiply by 4 bytes per int */
- sll %g4, 2, %g4
- add %g3, %g4, %g3
- st %sp, [%g3]
-
- /*
- * Now save to internal buffer.
- */
- sethi %hi(_machCurStatePtr), %g3
- ld [%g3 + %lo(_machCurStatePtr)], %g3
- add %g3, MACH_SAVED_REGS_OFFSET, %g3
- /*
- * Current window * 4 bytes per reg is still in %g4. Now we just
- * need to multiply it by the number of registers per window.
- */
- sll %g4, MACH_NUM_REG_SHIFT, %g4
- add %g3, %g4, %g3 /* offset to start saving at */
- MACH_SAVE_WINDOW_TO_BUFFER(%g3)
- set ReturnFromOverflow, %g3
- jmp %g3
- nop
- NormalOverflow:
- /*
- * Save this window to stack - save locals and ins to top 16 words
- * on the stack. (Since our stack grows down, the top word is %sp
- * and the bottom will be (%sp + offset).
- */
- MACH_SAVE_WINDOW_TO_STACK()
- ReturnFromOverflow:
- restore /* move back to trap window */
- mov %VOL_TEMP1, %g3 /* restore global registers */
- mov %VOL_TEMP2, %g4
-
- /*
- * jump to calling routine - this may be a trap-handler or not.
- */
- jmp %SAFE_TEMP + 8
- nop
-
- /*
- * ----------------------------------------------------------------------
- *
- * MachHandleWindowUnderflowTrap --
- *
- * Trap entrance to the window underflow handler. This sets up a
- * return address, retreats a window, calls the underflow handler,
- * advances back to window in which we entered the routine, restores
- * the psr, and returns from the trap. We must retreat a window since
- * on a trap we are 2 windows away from the window to restore, but
- * on returning from a trap and checking if we need to restore a window,
- * we are only one window away. See the comments in MachWindowUnderflow()
- * for more details.
- * Because we must do some work in the window we were executing in when
- * we took a trap, we must make sure to save and restore the registers
- * we use there. This means clearing two globals out for this purpose.
- * We save and restore the globals in the actual trap window, since we
- * know we can use the local registers there freely. The underflow
- * routine expects its return address in %RETURN_ADDR_REG, so this is the
- * register we must save and restore in the inbetween window.
- *
- * In the case where the window we're restoring is for a user process,
- * we must also check for whether the stack is resident and writable.
- * If it isn't, we must page it in. To do this is gross. Since the
- * trap window we've entered into is 2 windows away from the window to
- * restore, we must move back one window and check the %fp there. (This
- * will be the %sp in the actual window to restore.) If it isn't
- * resident, then we must move forward again to the trap window and call
- * MachTrap to save state for us. Then we can call the Vm_PageIn code
- * from the trap window to page in the nasty stuff. If it fails, we
- * must kill the user process. All of this is complicated a bit further
- * by the fact that we have 2 addresses to test: the %fp and the
- * %fp + the size of the saved window stuff. So we check both for
- * residence. If both are okay, we just do normal underflow. If one or
- * the other fails, we save state. We then test the first address,
- * if it fails, we page it in. Then if the second one fails, we also
- * page it in. It most likely will have been paged in by the first one,
- * though. Then, after all this, we call the normal underflow which
- * should then be protected from page faults. It has to be, since
- * it operates in one window back from the trap window where we saved
- * state, and we can't have any calls to Vm code there overwriting our
- * saved state. Then we return. If we marked that we had to save
- * state, then we must restore state by calling MachReturnFromTrap and
- * leaving as if this had all been a slow trap instead. Unfortunately,
- * we must test some stuff twice, since there are no registers to save
- * anything into (%VOL_TEMP registers are blasted by the MachTrap code,
- * and the SAFE_TEMP register is already used to mark whether we saved
- * state).
- *
- * NOTE: In the case where we must save state by calling MachTrap,
- * a lot of the underflow code is duplicated in MachReturnFromTrap,
- * which we also end up calling. The reason I cannot simply call
- * MachReturnFrom trap then to do all that work, is that I must do the
- * work in one window away in the case of a real underflow trap. There
- * may be a way to deal with this, but I haven't done it yet.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The window in question is restored.
- *
- * ----------------------------------------------------------------------
- */
- .global MachHandleWindowUnderflowTrap
- MachHandleWindowUnderflowTrap:
- /*
- * We need a global to mark further actions, and a global to save
- * the fp in if we find it needs to be page faulted. We can save one
- * global in SAFE_TEMP since it's only whacked by MachTrap, which is
- * the only thing that might whack it, in case MachTrap gets an
- * overflow. But we won't get one since this is an underflow trap.
- * %o5 also appears to be safe here since it is not overwritten
- * by parameters to Vm_PageIn, etc. We also need 2 more globals for
- * checking whether the stack will cause a fault. We use a few more
- * out registers that we hope Vm_PageIn won't trash. NOTE: WE ARE
- * MAKING AN ASSUMPTION that Vm_PageIn isn't compiled to mess with its
- * in registers. If we switch compilers, this may break!!!
- */
- mov %g3, %SAFE_TEMP
- mov %g4, %o5
- mov %g2, %o3
- mov %g5, %o4
-
- /* Test if we came from user mode. */
- andcc %CUR_PSR_REG, MACH_PS_BIT, %g0
- bne NormalUnderflow
- nop
-
- /*
- * Test if stack is resident for window we need to restore.
- * This means move back a window and test its frame pointer since
- * we've trapped into a window 2 away from the one whose stack is
- * in question.
- */
- restore
- /*
- * If the alignment of the user stack pointer is bad, kill the process!
- * We must be back in the trap window to do that.
- */
- andcc %fp, 0x7, %g0
- be,a CheckForFaults
- clr %g3 /* g3 clear for no problem yet */
- mov 0x1, %g3 /* Mark why we will save state */
- bne,a MustSaveState
- save /* back to trap window, in annulled delay slot */
-
- CheckForFaults:
- /*
- * %g3 will have have a record of what faults would occur.
- */
- MACH_CHECK_STACK_FAULT(%fp, %g2, %g3, %g5, UndflFault1, UndflFault2)
- mov %fp, %g4 /* in case we need to fault it */
- be NormalUnderflow
- save /* back to trap window */
-
- MustSaveState:
- /*
- * We need to save state. We must do this in actual trap window.
- * This state-saving enables traps. We will return to
- * MachReturnToUnderflowWithSavedState
- */
- call _MachTrap
- nop
- MachReturnToUnderflowWithSavedState:
- /*
- * We had to save state for some reason. %g3 contains the reason
- * why.
- */
- cmp %g3, 0x1
- be KillTheProc
- nop
- andcc %g3, 0x2, %g0
- be CheckNextUnderflow /* It wasn't first possible fault */
- nop
-
- QUICK_ENABLE_INTR(%VOL_TEMP1)
- /* Address that would fault is in %g4. */
- mov %g4, %o0
- clr %o1 /* also check protection???? */
- call _Vm_PageIn, 2
- nop
- QUICK_DISABLE_INTR(%VOL_TEMP1)
- tst %RETURN_VAL_REG
- be CheckNextUnderflow /* succeeded, try next */
- nop
- /* Otherwise, bad return, fall through to kill process. */
- KillTheProc:
- /* Need I restore all the global registers here since it's dying? */
-
- mov %SAFE_TEMP, %g3 /* restore g3 */
- mov %o5, %g4 /* restore g4 */
- mov %o3, %g2 /* etc */
- mov %o4, %g5
-
- /* KILL IT - must be in trap window */
- MACH_SR_HIGHPRIO() /* traps back on for overflow from printf */
- set _MachHandleWindowUnderflowDeathString, %o0
- call _printf, 1
- nop
- MACH_GET_CUR_PROC_PTR(%o0) /* procPtr in %o0 */
- sethi %hi(_machGenFlagsOffset), %o1
- ld [%o1 + %lo(_machGenFlagsOffset)], %o1
- add %o0, %o1, %o1
- ld [%o1], %o1
- sethi %hi(_machForeignFlag), %o2
- ld [%o2 + %lo(_machForeignFlag)], %o2
- andcc %o1, %o2, %o1 /* Is this a migrated proc? */
- be SuspendIt
- nop
- set PROC_TERM_DESTROYED, %o0 /* If so, kill it. */
- set PROC_BAD_STACK, %o1
- clr %o2
- call _Proc_ExitInt, 3
- nop
- SuspendIt: /* Else, make it debuggable. */
- MACH_GET_CUR_PROC_PTR(%o0) /* procPtr in %o0 */
- call _Sig_CheckForKill, 1 /* kill proc if KILL signal */
- nop
- MACH_GET_CUR_PROC_PTR(%o0) /* procPtr in %o0 */
- set TRUE, %o1 /* debug TRUE */
- set PROC_TERM_DESTROYED, %o2
- set PROC_BAD_STACK, %o3
- clr %o4
- call _Proc_SuspendProcess, 5
- nop
- ba SuspendIt /* proc should loop if continued */
- nop
-
- CheckNextUnderflow:
- andcc %g3, 0x4, %g0 /* See if second address would fault */
- be BackAgain
- nop
- QUICK_ENABLE_INTR(%VOL_TEMP1)
- /* old %fp is in %g4 */
- add %g4, (MACH_SAVED_WINDOW_SIZE - 4), %o0
- clr %o1 /* also check protection???? */
- call _Vm_PageIn, 2
- nop
- QUICK_DISABLE_INTR(%VOL_TEMP1)
- tst %RETURN_VAL_REG
- bne KillTheProc
- nop
- BackAgain:
- /*
- * Don't deal with underflow itself. Just pretend this was only
- * a stack page fault. User's restore instruction will get
- * re-executed and will cause a further underflow trap. This time,
- * the page should be there.
- */
-
- /* Restore globals */
- mov %SAFE_TEMP, %g3 /* restore g3 and g4 */
- mov %o5, %g4
- mov %o3, %g2
- mov %o4, %g5
-
- call _MachReturnFromTrap
- nop
-
- NormalUnderflow:
- restore /* retreat a window */
- /*
- * We need to preserve l6 and l7 in this window
- */
- mov %l6, %g2
- mov %l7, %g5
- mov %RETURN_ADDR_REG, %g3 /* save reg in global */
- set MachWindowUnderflow, %g4 /* put address in global */
- jmpl %g4, %RETURN_ADDR_REG /* our return addr to reg */
- nop
- mov %g3, %RETURN_ADDR_REG /* restore ret_addr */
- mov %g2, %l6
- mov %g5, %l7
- save /* back to trap window */
-
- /* Restore globals */
- mov %SAFE_TEMP, %g3 /* restore g3, g4, g2 & g5 */
- mov %o5, %g4
- mov %o3, %g2
- mov %o4, %g5
-
- MACH_RESTORE_PSR() /* restore psr */
- jmp %CUR_PC_REG /* return from trap */
- rett %NEXT_PC_REG
- nop
-
-
- /*
- * ----------------------------------------------------------------------
- *
- * MachWindowUnderflow --
- *
- * Window underflow handler. It's set up so that it can be called as a
- * result of a window underflow trap or as a result of needing to restore
- * an invalid window before returning from a trap or interrupt.
- * The address of the calling instruction is stored in %RETURN_ADDR_REG,
- * which is the normal place.
- *
- * The window we are in when we enter is one beyond the invalid window we
- * need to restore. On an underflow trap we enter the kernel 2 windows
- * away from the window that is invalid. (This is because we tried to
- * retreat to an invalid window and couldn't, so we trapped. Trapping
- * advances the current window, so we are 2 windows away from the invalid
- * window.) From the trap handler, then, we must retreat one window
- * before calling this routine so that we're only one window away from
- * the invalid window. Then after returning from here, we must do a
- * save to get back to our old trap window.
- *
- * First we mark the window behind the invalid window as the
- * new invalid window, and then we move to the invalid window. Then we
- * restore data from the stack into the invalid window. Then we return
- * to our previous window. Note that we first mark
- * the new invalid window and then move to the old invalid window. If
- * we did this in the other order, we'd get another window underflow trap.
- * (This is the opposite order from window overflow.)
- *
- * For the window to restore, the %sp should be good since it doesn't
- * get changed by these routines, even if it was a user window and this
- * is a kernel window.
- *
- * The %sp should point to highest (on stack, lowest in memory)
- * usable word in the current stack frame. %fp is the %sp of the
- * caller's stack frame, so the first (highest in memory) usable word
- * of a current stack frame is (%fp - 4).
- *
- * Results:
- * None.
- *
- * Side effects:
- * The window invalid mask changes and a register window is restored.
- *
- * ----------------------------------------------------------------------
- */
- .global MachWindowUnderflow
- MachWindowUnderflow:
- /*
- * Check to see if we're about to return to the trap window from
- * the debugger. If so, then the frame pointer should be equal
- * to the base of the debugger stack. If it is, change it to be
- * the top of the regular stack, so that when we return to the previous
- * window, our sp is at the top of the regular stack.
- * NOTE: The test below must agree with the amount we bump up the stack
- * by in MachTrap.
- */
- sethi %hi(_machDebugStackStart), %VOL_TEMP1
- /* base of stack */
- ld [%VOL_TEMP1 + %lo(_machDebugStackStart)], %VOL_TEMP1
- set MACH_FULL_STACK_FRAME, %VOL_TEMP2
- sub %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP1 /* offset from base */
- cmp %VOL_TEMP1, %fp
- bne RegularStack
- nop
-
- DealWithDebugStack:
- /* Set stack pointer of next window to regular frame pointer */
- sethi %hi(_machSavedRegisterState), %VOL_TEMP1
- ld [%VOL_TEMP1 + %lo(_machSavedRegisterState)], %fp
-
- RegularStack:
- /*
- * We assume that by the time we've gotten here, the stack has been
- * made resident, if it was a user stack, and we can just go blasting
- * ahead.
- *
- * It should be ok to use locals here - it's a dead window.
- * Note that this means one cannot do a restore and then a save
- * and expect that the old locals in the dead window are still the
- * same. That would be a really dumb thing to think anyway.
- */
- /* mark new invalid window */
- MACH_RETREAT_WIM(%VOL_TEMP1, %VOL_TEMP2)
-
- /* move to window to restore */
- restore
- /* restore data from stack to window - stack had better be resident! */
- MACH_RESTORE_WINDOW_FROM_STACK()
- /* Move back to previous window. Clear registers too??? */
- save
- /*
- * jump to calling routine - this may be a trap-handler or not.
- */
- jmp %RETURN_ADDR_REG + 8
- nop
-
-
-
- /*
- * ----------------------------------------------------------------------
- *
- * MachHandleDebugTrap --
- *
- * Enter the debugger. This means make sure all the windows are
- * saved to the stack, save my stack pointer, switch the stack pointer
- * to the debugger stack, and go.
- *
- * When we return, we change stack pointers and go to the usual
- * return from trap routine.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- * ----------------------------------------------------------------------
- */
- .global _MachHandleDebugTrap
- _MachHandleDebugTrap:
- /*
- * If we came from user mode, we do different stuff.
- */
- andcc %CUR_PSR_REG, MACH_PS_BIT, %g0 /* previous state? */
- bne KernelDebug /* was kernel mode */
- nop
- call _MachUserDebug
- nop
- set _MachReturnFromTrap, %VOL_TEMP1
- jmp %VOL_TEMP1
- nop
- KernelDebug:
- /*
- * This points to the top stack frame, which consists of a
- * Mach_RegState structure. This is handed to the debugger. We
- * also use this to restore our stack pointer upon returning from the
- * debugger.
- */
- sethi %hi(_machSavedRegisterState), %VOL_TEMP1
- st %sp, [%VOL_TEMP1 + %lo(_machSavedRegisterState)]
- /*
- * Now make sure all windows are flushed to the stack. We do this
- * with MACH_NUM_WINDOWS - 1 saves and restores. The window overflow
- * and underflow traps will then handle this for us. We put the counter
- * in a global, since they have all been saved already and are free
- * for our use and we need the value across windows.
- */
-
- sethi %hi(_machNumWindows), %g2
- ld [%g2 + %lo(_machNumWindows)], %g2
- sub %g2, 1, %g1
- SaveSomeMore:
- save
- subcc %g1, 1, %g1
- bne SaveSomeMore
- nop
- sub %g2, 1, %g1
- RestoreSomeMore:
- restore
- subcc %g1, 1, %g1
- bne RestoreSomeMore
- nop
-
- /* Set stack base for debugger */
- sethi %hi(_machDebugStackStart), %VOL_TEMP1
- /* stack base */
- ld [%VOL_TEMP1 + %lo(_machDebugStackStart)], %VOL_TEMP1
- set MACH_FULL_STACK_FRAME, %VOL_TEMP2
- sub %VOL_TEMP1, %VOL_TEMP2, %sp /* offset from base */
- /* get trap type into o0 from local saved value */
- and %CUR_TBR_REG, MACH_TRAP_TYPE_MASK, %o0
- srl %o0, 4, %o0
- /* put saved reg ptr into o1 */
- sethi %hi(_machSavedRegisterState), %VOL_TEMP1
- ld [%VOL_TEMP1 + %lo(_machSavedRegisterState)], %o1
- /*
- * Set wim to this window, so that when we return from debugger,
- * we'll restore the registers for this window from the stack state
- * handled by the debugger. This is safe to do before calling the
- * debugger, since we just saved all the windows to the stack.
- */
- MACH_SET_WIM_TO_CWP()
- /*
- * Is there a window of vulnerability here when the sp doesn't match
- * what's saved on the stack and I might restore incorrectly from
- * stack if I took another trap? But interrupts should be off and
- * I shouldn't get a trap.
- */
-
- /* call debugger */
- call _Dbg_Main,2
- nop
-
- /* put saved stack pointer into %sp. */
- sethi %hi(_machSavedRegisterState), %VOL_TEMP1
- ld [%VOL_TEMP1 + %lo(_machSavedRegisterState)], %sp
-
- /* finish as for regular trap */
- set _MachReturnFromTrap, %VOL_TEMP1
- jmp %VOL_TEMP1
- nop
-
-
- /*
- * ----------------------------------------------------------------------
- *
- * MachSyscallTrap --
- *
- * This is the code to handle system call traps. The number of the
- * system call is in %g1.
- *
- * Results:
- * Returns a status to the caller in the caller's %o0 (or %i0).
- *
- * Side effects:
- * Depends on the kernel call.
- *
- * ----------------------------------------------------------------------
- */
- .global MachSyscallTrap
- MachSyscallTrap:
- /*
- * So that we don't re-execute the trap instruction when we
- * return from the system call trap via the return trap procedure,
- * we increment the return pc and npc here.
- */
- mov %NEXT_PC_REG, %CUR_PC_REG
- add %NEXT_PC_REG, 0x4, %NEXT_PC_REG
- /*
- * Make sure user stack pointer is written into state structure so that
- * it can be used while processing the system call. (Who uses it??)
- * This means saving the frame pointer (previous user stack pointer).
- */
- MACH_GET_CUR_STATE_PTR(%VOL_TEMP1, %VOL_TEMP2) /* into %VOL_TEMP1 */
- add %VOL_TEMP1, MACH_TRAP_REGS_OFFSET, %VOL_TEMP1
- ld [%VOL_TEMP1], %VOL_TEMP1
- add %VOL_TEMP1, MACH_FP_OFFSET, %VOL_TEMP1
- st %fp, [%VOL_TEMP1]
- /* If fork call, save registers and invalidate trapRegs stuff????? */
- /*
- * Check number of kernel call for validity. This was stored in %g1.
- * We must be careful not to have trashed it. But if we end up
- * trashing it, we could instead pull it out of the saved globals state
- * in the mach state structure since it got saved there.
- */
- set _machMaxSysCall, %VOL_TEMP1
- ld [%VOL_TEMP1], %VOL_TEMP1
- cmp %VOL_TEMP1, %g1
- bgeu GoodSysCall
- nop
- /*
- * If bad, (take user error? - on spur) then do normal return from trap.
- * Is this magic number a return value? It's in the sun3 code.
- */
- set SYS_INVALID_SYSTEM_CALL, %RETURN_VAL_REG
- set ReturnFromSyscall, %VOL_TEMP1
- jmp %VOL_TEMP1
- nop
- GoodSysCall:
- /*
- * Save sys call number into lastSysCall field in process state so
- * that migration can figure out what it was supposed to be.
- * %g1 must still contain syscall number.
- */
- MACH_GET_CUR_STATE_PTR(%VOL_TEMP1, %VOL_TEMP2) /* into %VOL_TEMP1 */
- set _machLastSysCallOffset, %VOL_TEMP2
- ld [%VOL_TEMP2], %VOL_TEMP2
- add %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP1
- st %g1, [%VOL_TEMP1]
- /*
- * Fetch args. Copy them from user space if they aren't all in
- * the input registers. For now I copy all the input registers,
- * since there isn't a table giving the actual number of args?
- * For args beyond the number of words that can fit in the input
- * registers, I get the offset to copy to and the pc to jump to inside
- * the copying from tables set up in Mach_SyscallInit. If there
- * are no args to copy, then the pc gets set to jump to
- * MachFetchArgsEnd.
- */
- mov %i5, %o5
- mov %i4, %o4
- mov %i3, %o3
- mov %i2, %o2
- mov %i1, %o1
- mov %i0, %o0
- /*
- * Fetch offsets to copy from and to out of table.
- */
- sll %g1, 2, %g1 /* system call index */
- set _machArgOffsets, %VOL_TEMP2 /* offset in table */
- add %g1, %VOL_TEMP2, %VOL_TEMP2 /* addr in table */
- ld [%VOL_TEMP2], %VOL_TEMP2 /* offset value */
- add %fp, %VOL_TEMP2, %VOL_TEMP1 /* need global here? */
- add %sp, %VOL_TEMP2, %VOL_TEMP2 /* need global here? */
-
- /*
- * Fetch pc branch address out of table and put it into %SAFE_TEMP
- */
- set _machArgDispatch, %SAFE_TEMP
- add %g1, %SAFE_TEMP, %SAFE_TEMP
- ld [%SAFE_TEMP], %SAFE_TEMP
- jmp %SAFE_TEMP
- nop
-
- .global _MachFetchArgs
- _MachFetchArgs:
- ld [%VOL_TEMP1], %SAFE_TEMP /* first word - pc offset 0 */
- st %SAFE_TEMP, [%VOL_TEMP2]
- add %VOL_TEMP1, 4, %VOL_TEMP1
- add %VOL_TEMP2, 4, %VOL_TEMP2
- ld [%VOL_TEMP1], %SAFE_TEMP /* second word - pc offset 16 */
- st %SAFE_TEMP, [%VOL_TEMP2]
- add %VOL_TEMP1, 4, %VOL_TEMP1
- add %VOL_TEMP2, 4, %VOL_TEMP2
- ld [%VOL_TEMP1], %SAFE_TEMP /* third word - pc offset 32 */
- st %SAFE_TEMP, [%VOL_TEMP2]
- add %VOL_TEMP1, 4, %VOL_TEMP1
- add %VOL_TEMP2, 4, %VOL_TEMP2
- ld [%VOL_TEMP1], %SAFE_TEMP /* fourth word */
- st %SAFE_TEMP, [%VOL_TEMP2]
- add %VOL_TEMP1, 4, %VOL_TEMP1
- add %VOL_TEMP2, 4, %VOL_TEMP2
- ld [%VOL_TEMP1], %SAFE_TEMP /* fifth word */
- st %SAFE_TEMP, [%VOL_TEMP2]
- add %VOL_TEMP1, 4, %VOL_TEMP1
- add %VOL_TEMP2, 4, %VOL_TEMP2
- ld [%VOL_TEMP1], %SAFE_TEMP /* sixth word */
- st %SAFE_TEMP, [%VOL_TEMP2]
- add %VOL_TEMP1, 4, %VOL_TEMP1
- add %VOL_TEMP2, 4, %VOL_TEMP2
- ld [%VOL_TEMP1], %SAFE_TEMP /* seventh word */
- st %SAFE_TEMP, [%VOL_TEMP2]
- add %VOL_TEMP1, 4, %VOL_TEMP1
- add %VOL_TEMP2, 4, %VOL_TEMP2
- ld [%VOL_TEMP1], %SAFE_TEMP /* eighth word */
- st %SAFE_TEMP, [%VOL_TEMP2]
- add %VOL_TEMP1, 4, %VOL_TEMP1
- add %VOL_TEMP2, 4, %VOL_TEMP2
- ld [%VOL_TEMP1], %SAFE_TEMP /* ninth word */
- st %SAFE_TEMP, [%VOL_TEMP2]
- add %VOL_TEMP1, 4, %VOL_TEMP1
- add %VOL_TEMP2, 4, %VOL_TEMP2
- ld [%VOL_TEMP1], %SAFE_TEMP /* tenth word */
- st %SAFE_TEMP, [%VOL_TEMP2]
- add %VOL_TEMP1, 4, %VOL_TEMP1
- add %VOL_TEMP2, 4, %VOL_TEMP2
- /*
- * Marks last place where PC could be when a page fault occurs while
- * fetching arguments. Needed to distinguish between a page fault
- * during arg fetch (which is okay) from other page faults in the
- * kernel, which are fatal errors.
- */
- .global _MachFetchArgsEnd
- _MachFetchArgsEnd:
- /* get address from table */
- MACH_GET_CUR_PROC_PTR(%VOL_TEMP1) /* into %VOL_TEMP1 */
- set _machKcallTableOffset, %VOL_TEMP2
- ld [%VOL_TEMP2], %VOL_TEMP2 /* offset to kcalls */
- add %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP1
- ld [%VOL_TEMP1], %VOL_TEMP1 /* addr of array */
- add %g1, %VOL_TEMP1, %VOL_TEMP1 /* index to kcall */
- ld [%VOL_TEMP1], %VOL_TEMP1 /* got addr */
- /* enable interrupts */
- QUICK_ENABLE_INTR(%VOL_TEMP2)
- /* go do it */
- call %VOL_TEMP1
- nop
- ReturnFromSyscall:
- /* Disable interrupts. */
- QUICK_DISABLE_INTR(%VOL_TEMP1)
- /*
- * Move return value to caller's return val register.
- */
- mov %RETURN_VAL_REG, %RETURN_VAL_REG_CHILD
- /*
- * Sun3 checks special handling flag here. I do it in return from
- * trap, if we came from a user process.
- */
-
- /* restore the stack pointers? */
-
- /* do normal return from trap */
- set _MachReturnFromTrap, %VOL_TEMP1
- jmp %VOL_TEMP1
- nop
-
- /*
- * ----------------------------------------------------------------------
- *
- * MachLinkTrap --
- *
- * This is the code to handle a dynamic linking trap #2.
- * Apparently we don't have to do anything.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- * ----------------------------------------------------------------------
- */
- .global MachLinkTrap
- MachLinkTrap:
- /*
- * So that we don't re-execute the trap instruction when we
- * return from the system call trap via the return trap procedure,
- * we increment the return pc and npc here.
- */
- mov %NEXT_PC_REG, %CUR_PC_REG
- add %NEXT_PC_REG, 0x4, %NEXT_PC_REG
-
- /* do normal return from trap */
- set _MachReturnFromTrap, %VOL_TEMP1
- jmp %VOL_TEMP1
- nop
-
- /*
- * ----------------------------------------------------------------------
- *
- * MachUnixSyscallTrap --
- *
- * This is the code to handle unix system call traps. The number of the
- * system call is in %g1.
- *
- * Results:
- * Returns a status to the caller in the caller's %o0 (or %i0).
- *
- * Side effects:
- * Depends on the kernel call.
- *
- * ----------------------------------------------------------------------
- */
- .global MachUnixSyscallTrap
- MachUnixSyscallTrap:
- /*
- * So that we don't re-execute the trap instruction when we
- * return from the system call trap via the return trap procedure,
- * we increment the return pc and npc here.
- */
- mov %NEXT_PC_REG, %CUR_PC_REG
- add %NEXT_PC_REG, 0x4, %NEXT_PC_REG
- /*
- * Make sure user stack pointer is written into state structure so that
- * it can be used while processing the system call. (Who uses it??)
- * This means saving the frame pointer (previous user stack pointer).
- */
- MACH_GET_CUR_STATE_PTR(%VOL_TEMP1, %VOL_TEMP2) /* into %VOL_TEMP1 */
- add %VOL_TEMP1, MACH_TRAP_REGS_OFFSET, %VOL_TEMP1
- ld [%VOL_TEMP1], %VOL_TEMP1
- add %VOL_TEMP1, MACH_FP_OFFSET, %VOL_TEMP1
- st %fp, [%VOL_TEMP1]
- nop
- /* If fork call, save registers and invalidate trapRegs stuff????? */
- /*
- * Check number of kernel call for validity. This was stored in %g1.
- * We must be careful not to have trashed it. But if we end up
- * trashing it, we could instead pull it out of the saved globals state
- * in the mach state structure since it got saved there.
- */
- set _sysUnixNumSyscalls, %VOL_TEMP1
- ld [%VOL_TEMP1], %VOL_TEMP1
- cmp %VOL_TEMP1, %g1
- bgeu GoodUnixSysCall
- nop
- /*
- * If bad, (take user error? - on spur) then do normal return from trap.
- * Is this magic number a return value? It's in the sun3 code.
- */
- set -1, %RETURN_VAL_REG
- set ReturnFromUnixSyscall, %VOL_TEMP1
- jmp %VOL_TEMP1
- nop
- GoodUnixSysCall:
- /*
- * Save sys call number into lastSysCall field in process state so
- * that migration can figure out what it was supposed to be.
- * %g1 must still contain syscall number.
- */
- MACH_GET_CUR_STATE_PTR(%VOL_TEMP1, %VOL_TEMP2) /* into %VOL_TEMP1 */
- set _machLastSysCallOffset, %VOL_TEMP2
- ld [%VOL_TEMP2], %VOL_TEMP2
- add %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP1
- st %g1, [%VOL_TEMP1]
- /*
- * Save i0 for call restart.
- */
- st %i0, [%VOL_TEMP1+4]
- /*
- * Fetch args. Copy them from user space if they aren't all in
- * the input registers. For now I copy all the input registers,
- * since there isn't a table giving the actual number of args?
- * For args beyond the number of words that can fit in the input
- * registers, I get the offset to copy to and the pc to jump to inside
- * the copying from tables set up in Mach_SyscallInit. If there
- * are no args to copy, then the pc gets set to jump to
- * MachFetchArgsEnd.
- */
- mov %i5, %o5
- mov %i4, %o4
- mov %i3, %o3
- mov %i2, %o2
- mov %i1, %o1
- mov %i0, %o0
-
- cmp %g1, 0x8b /* Sigreturn */
- be DoSigreturn
-
- sll %g1, 3, %g1
- set _sysUnixSysCallTable, %VOL_TEMP2
- add %g1, %VOL_TEMP2, %VOL_TEMP2 /* index to kcall */
- ld [%VOL_TEMP2], %VOL_TEMP2 /* got addr */
- /* enable interrupts */
- QUICK_ENABLE_INTR(%VOL_TEMP1)
- /* go do it */
- call %VOL_TEMP2
- nop
- ReturnFromUnixSyscall:
- /* Disable interrupts. */
- QUICK_DISABLE_INTR(%VOL_TEMP1)
- /*
- * Move return value to caller's return val register.
- */
-
- /*
- * Check if error.
- */
- cmp %RETURN_VAL_REG, -1
- bne UnixOk
- nop
-
- /*
- * Get the errno from the pcb and use it as the return value.
- */
- MACH_GET_CUR_PROC_PTR(%VOL_TEMP1) /* into %VOL_TEMP1 */
- set MACH_UNIX_ERRNO_OFFSET, %VOL_TEMP2
- add %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP1
- ld [%VOL_TEMP1], %VOL_TEMP1
- mov %VOL_TEMP1, %RETURN_VAL_REG_CHILD
-
- /*
- * Set the carry to indicate an error.
- */
- mov %CUR_PSR_REG, %VOL_TEMP2
- set MACH_CARRY_BIT, %VOL_TEMP1
- or %VOL_TEMP2, %VOL_TEMP1, %VOL_TEMP2
- mov %VOL_TEMP2, %CUR_PSR_REG
- set _MachReturnFromTrap, %VOL_TEMP1
- jmp %VOL_TEMP1
- nop
-
- UnixOk:
- mov %RETURN_VAL_REG, %RETURN_VAL_REG_CHILD
- mov %o1, %i1
- mov %CUR_PSR_REG, %VOL_TEMP2
- set MACH_CARRY_BITMASK, %VOL_TEMP1
- and %VOL_TEMP2, %VOL_TEMP1, %VOL_TEMP2
- mov %VOL_TEMP2, %CUR_PSR_REG
- set _MachReturnFromTrap, %VOL_TEMP1
- jmp %VOL_TEMP1
- nop
-
- DoSigreturn:
- /* We have to skip the errno checking */
- QUICK_ENABLE_INTR(%VOL_TEMP1)
- /* go do it */
- call _Mach_SigreturnStub
- nop
- MACH_RESTORE_WINDOW_FROM_STACK()
- /* Disable interrupts. */
- QUICK_DISABLE_INTR(%VOL_TEMP1)
- set _MachReturnFromTrap, %VOL_TEMP1
- jmp %VOL_TEMP1
- nop
-
-
- /*
- * ----------------------------------------------------------------------
- *
- * MachHandlePageFault --
- *
- * An instruction or data fault has occurred. This routine will retrieve
- * the fault error from the bus error register and the faulting address
- * from the address error register and will call
- * Vm routines to handle faulting in the page.
- *
- * Results:
- * Returns to MachReturnFromTrap rather than its caller.
- *
- * Side effects:
- * The page that caused the fault will become valid.
- *
- * ----------------------------------------------------------------------
- */
- .global MachHandlePageFault
- MachHandlePageFault:
- #ifdef sun4c
- /* synchronous error register value as first arg - clears it too. */
- set VMMACH_SYNC_ERROR_REG, %o0
- lda [%o0] VMMACH_CONTROL_SPACE, %o0
-
- /* synch error address register value as second arg - clears it. */
- set VMMACH_SYNC_ERROR_ADDR_REG, %o1
- lda [%o1] VMMACH_CONTROL_SPACE, %o1
-
- /* clear async regs as well since they latch on sync errors as well. */
- set VMMACH_ASYNC_ERROR_REG, %VOL_TEMP1
- lda [%VOL_TEMP1] VMMACH_CONTROL_SPACE, %g0
-
- /* async error addr reg as well, so clear it. Very silly. */
- set VMMACH_ASYNC_ERROR_ADDR_REG, %VOL_TEMP1
- lda [%VOL_TEMP1] VMMACH_CONTROL_SPACE, %g0
- #else
- /* bus error register value as first arg. */
- set VMMACH_BUS_ERROR_REG, %o0
- lduba [%o0] VMMACH_CONTROL_SPACE, %o0
-
- /* memory address causing the error as second arg */
- set VMMACH_ADDR_ERROR_REG, %o1
- ld [%o1], %o1
-
- /* Write the address register to clear it */
- set VMMACH_ADDR_ERROR_REG, %VOL_TEMP1
- st %o1, [%VOL_TEMP1]
- #endif
- /* trap value of the psr as third arg */
- mov %CUR_PSR_REG, %o2
-
- /* trap value of pc as fourth argument */
- mov %CUR_PC_REG, %o3
- #ifndef sun4c
- /*
- * If the trap was on a pc access rather than a data access, the
- * memoory address register won't have frozen the correct address.
- * Just move the pc into the second argument.
- */
- and %CUR_TBR_REG, MACH_TRAP_TYPE_MASK, %VOL_TEMP1
- cmp %VOL_TEMP1, MACH_INSTR_ACCESS
- bne AddressValueOkay
- nop
- mov %CUR_PC_REG, %o1
- #endif
- AddressValueOkay:
- /* enable interrupts */
- /*
- QUICK_ENABLE_INTR(%VOL_TEMP1)
- */
- call _MachPageFault, 4
- nop
- /* Disable interrupts. */
- QUICK_DISABLE_INTR(%VOL_TEMP1)
-
- set _MachReturnFromTrap, %VOL_TEMP1
- jmp %VOL_TEMP1
- nop
-
-
- /*
- * ----------------------------------------------------------------------
- *
- * MachFlushWindowsToStackTrap --
- *
- * A trap requesting that all our windows be flushed to the stack has
- * occured. Bump up our return pc, since we don't want to re-execute
- * the trap, and then call the appropriate routine.
- *
- * Results:
- * Returns to MachReturnFromTrap, rather than our caller.
- *
- * Side effects:
- * Register windows will be flushed to the stack and the invalid
- * window mask will be set to point to the window before us.
- *
- * ----------------------------------------------------------------------
- */
- .global MachFlushWindowsToStackTrap
- MachFlushWindowsToStackTrap:
- mov %NEXT_PC_REG, %CUR_PC_REG
- add %NEXT_PC_REG, 4, %NEXT_PC_REG
- call _Mach_FlushWindowsToStack
- nop
- set _MachReturnFromTrap, %VOL_TEMP1
- jmp %VOL_TEMP1
- nop
-